/*
 * macaroon.h
 *
 *  Created on: Mar 19, 2017
 *      Author: hp
 */

#ifndef SRC_MACAROON_H_
#define SRC_MACAROON_H_

#include <stddef.h>

#include <string>
#include <vector>
#include <utility>

#include <sodium/crypto_box.h>
#include <stdexcept>

namespace c_macaroons {
struct macaroon;
struct macaroon_verifier;
}

#include "exceptions.h"

namespace macaroons {

#define MACAROON_SUGGESTED_SECRET_LENGTH 32

struct third_party_caveat {
	third_party_caveat(std::string l, std::string i) :
			location(l), identifier(i) {
	}

	third_party_caveat(std::string& l, std::string& i) :
			location(l), identifier(i) {
	}

	std::string location;
	std::string identifier;
};

typedef std::vector<third_party_caveat> third_party_caveat_list;

class verifier;

class macaroon {
	friend class verifier;
public:
	macaroon(const macaroon& rhs);
	macaroon(std::string location, std::string key, std::string id);
	macaroon(const char* location, size_t location_sz, const char* key,
			size_t key_sz, const char* id, size_t id_sz);
	macaroon(const unsigned char* location, size_t location_sz,
			const unsigned char* key, size_t key_sz, const unsigned char* id,
			size_t id_sz);
	macaroon(std::string data);

	void add_first_party_caveat(std::string predicate);
	void add_first_party_caveat(const char* predicate, size_t predicate_sz);
	void add_third_party_caveat(std::string location, std::string key,
			std::string id);
	void add_third_party_caveat(const char* location, size_t location_sz,
			const char *key, size_t key_sz, const char* id, size_t id_sz);
	void add_third_party_caveat(const char* location, size_t location_sz,
			const unsigned char *key, size_t key_sz, const unsigned char* id,
			size_t id_sz);
	void add_third_party_caveat_with_keypair(std::string location,
			unsigned char pk[crypto_box_PUBLICKEYBYTES],
			unsigned char sk[crypto_box_SECRETKEYBYTES]);

	third_party_caveat_list third_party_caveats() const;

	macaroon prepare_for_request(const macaroon& d) const;

	std::string inspect() const;
	std::string serialize() const;
	bool validate() const;

	std::string location() const;
	std::string identifier() const;

	macaroon operator=(const macaroon& rhs);
	bool operator==(const macaroon& rhs) const;
	bool has_third_party_caveats() const;

	~macaroon();
private:
	macaroon();

	void create(const unsigned char* location, size_t location_sz,
			const unsigned char* key, size_t key_sz, const unsigned char* id,
			size_t id_sz);

	c_macaroons::macaroon* m;
};

macaroon macaroon_discharge(std::string location, std::string secret,
		unsigned char pk[crypto_box_PUBLICKEYBYTES],
		unsigned char sk[crypto_box_SECRETKEYBYTES]);

typedef std::vector<macaroon> macaroon_list;

class verifier {
public:
	verifier();

	void satisfy_exact(const std::string predicate);

	bool verify(const macaroon& m, const std::string key) const;
	bool verify(const macaroon& m, const std::string key,
			macaroon_list third_party_caveats) const;

	~verifier();
private:
	c_macaroons::macaroon_verifier* v;
};

} // namespace macaroons

#endif /* SRC_MACAROON_H_ */
